package com.wallace.downloadserver.controller

import com.wallace.downloadserver.annotation.VerifyToken
import com.wallace.downloadserver.myconst.DefineName
import com.wallace.downloadserver.netty.NettyConfig
import com.wallace.downloadserver.pojo.LoggedInUser
import com.wallace.downloadserver.pojo.LoginData
import com.wallace.downloadserver.redis.RedisManager
import com.wallace.downloadserver.redis.getV
import com.wallace.downloadserver.redis.setExpire
import com.wallace.downloadserver.redis.setV
import com.wallace.downloadserver.service.MyInterfaceService
import com.wallace.downloadserver.service.UserService
import com.wallace.downloadserver.template.ResponseTemplate
import com.wallace.downloadserver.util.HttpUtil
import com.wallace.downloadserver.util.myJson.JsonUtil
import com.wallace.downloadserver.util.myToken.TokenContent
import com.wallace.downloadserver.util.myToken.TokenUtil
import net.minidev.json.JSONObject
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.web.bind.annotation.*
import java.util.concurrent.TimeUnit
import javax.servlet.http.HttpServletRequest

@RestController
@RequestMapping(value = ["/downloadserver/api/login"], produces = ["application/json; charset=utf-8"])
class LoginController {

    private val log: Logger = LoggerFactory.getLogger(LoginController::class.java)

    private var redisTokenDB: RedisTemplate<String, Any>? = null

    @Autowired
    private fun setRedisTokenDB(redisManager: RedisManager) {
        redisTokenDB = redisManager.getTokenDB()
    }

    private var redisAesKeyDB: RedisTemplate<String, Any>? = null

    @Autowired
    private fun setRedisAesKeyDB(redisManager: RedisManager) {
        redisAesKeyDB = redisManager.getAesKeyDB()
    }

    private var redisNettyAesKeyDB: RedisTemplate<String, Any>? = null

    @Autowired
    private fun setRedisNettyAesKeyDB(redisManager: RedisManager) {
        redisNettyAesKeyDB = redisManager.getNettyAesKeyDB()
    }

    @Autowired
    private val userService: UserService? = null

    @Autowired
    private val myInterfaceService: MyInterfaceService? = null

    @Autowired
    private val nettyConfig: NettyConfig? = null

    /**
     * 登陆成功，生成token，用于建立Netty通道以及后续通信
     */
    @RequestMapping(value = ["/login", "/login1"], method = [RequestMethod.POST])
    fun login(@RequestBody data: String,
              @RequestAttribute(value = DefineName.RSA_PRIVATE_KEY) privateKey: String,
              @RequestAttribute(value = DefineName.AES_KEY) aesKey: String,
              @RequestAttribute(value = DefineName.AES_IV) iv: String): ResponseTemplate {
        val loginData = JsonUtil.toAny(data, LoginData::class.java)
        val user = loginData?.let { userService!!.selectByLoginData(it) }
        return if (user == null) {
            log.info("用户[username = ${loginData?.username},password = ${loginData?.password}]不存在")
            ResponseTemplate("用户信息不存在")
        } else {
            // 保存RSA私钥,AES密钥和iv，时效为：30min
            val keyMap = mapOf(
                    DefineName.RSA_PRIVATE_KEY to privateKey,
                    DefineName.AES_KEY to aesKey,
                    DefineName.AES_IV to iv
            )
            log.debug("keyMap = $keyMap")
            redisAesKeyDB!!.setV(user.uid, keyMap, TimeUnit.MINUTES.toMillis(30))
            val path = myInterfaceService!!.selectMethodName("getNettyConfig")?.path ?: listOf()
            val nettyToken = TokenUtil.signNettyToken(user, path)
            val loggedInUser = LoggedInUser(userId = user.uid, displayName = user.name,
                    token = nettyToken ?: "", urls = mapOf(
                    "getNettyConfig" to path
            ))
            log.info("${user}登录成功")
            ResponseTemplate("登录成功", JsonUtil.toJson(loggedInUser))
        }
    }

    /**
     * 返回Netty的配置
     */
    @VerifyToken
    @RequestMapping(value = ["/getNettyConfig", "getNettyConfig1"], method = [RequestMethod.GET])
    fun getNettyConfig(request: HttpServletRequest, @RequestAttribute(value = DefineName.TOKEN_CONTENT) tokenContent: TokenContent): ResponseTemplate {
        // 刷新token时间
        redisTokenDB!!.setExpire(tokenContent.id, TokenUtil.LIMIT_TOKEN_TIME)
        val uid = tokenContent.id.split("-")[1]
        val map = redisAesKeyDB!!.getV(uid) as Map<*, *>
        val ip = HttpUtil.getRealIp(request)
        redisNettyAesKeyDB!!.setV(ip, map)
        val data = JSONObject()
        data["host"] = nettyConfig!!.host
        data["port"] = nettyConfig.port
        return ResponseTemplate(data = data.toJSONString())
    }
}